package interfaz2;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

/**
 * This class is intended to manage various views from different view
 * components and make it easy to change from one view to another.
 * 
 * You will want to use it when you want to have an area of your GUI able to
 * show a range of components (i.e. a label, a table, a tree, etc...) just one
 * at a time, making possible changing the views between them easy.
 * 
 * Right now when new Controls are added to this Composite you will need to
 * hide them explicitly. This is necessary until we discover how to add a
 * Listener to this class for when a child is added to it, so i can hide
 * that child... SWT FUCK YEAH! ¬¬
 * 
 * @author ole
 */
public class MultiViewComposite extends DustComposite {
	// Class attributes.
	private int actual_view = -1;
	
	/**
	 * This class handles when a child of this MultiViewComposite is
	 * dispose in order to ensure that this child being disposed is not
	 * the actual view and if so, change the view.
	 * 
	 * This Listener must be added to all the children of the
	 * MultiViewComposite this Listener explicitly. Yes, this sounds like a
	 * joke but it is not. SWT has no way to know when a Control inside a
	 * Composite has been added, disposed, etc...
	 */
	public class ChildDisposeListener implements DisposeListener {
		@Override
		public void widgetDisposed(DisposeEvent event) {
			Control child;
			GridData grid;
			int index;
			
			// Search the child index.
			child = (Control)event.getSource();
			index = -1;
			for (Control control: getChildren()) {
				if (control.equals(child)) {
					index++;
					break;
				}
				
				index++;
			}
			
			// Really weird, this handler has been call from a Control that
			// is not in this MultiViewComposite. Are you using them right?
			if (index == -1)
				throw new RuntimeException("Tried to dipose a Control that " +
										   "wasn't inside the " +
										   "MultiViewComposite.\nHow is this" +
										   "possible?!");
			
			// If the child to be disposed is the same that is being shown
			// change it to show nothing.
			if (actual_view == index) {
				actual_view = -1;
				grid = new GridData(SWT.FILL, SWT.FILL, true, true);
				grid.exclude = true;
				child.setLayoutData(grid);
				child.setVisible(false);
				layout();
			}
			
			// If the child to be disposed has an index among the
			// MultiViewComposite children lower than the actual view will
			// cause that "actual_view" needs to be decrease. This is because
			// since we are disposing a lower index Control the Control of the
			// actual view being shown will be moved one position before, if
			// we don't, later when we tried to change the view we can obtain
			// an IndexOutOfBoundsException.
			if (index < actual_view)
				actual_view--;
		}
	}
	
	/*
	 * Public methods of MultiViewComposite class.
	 */
	
	/**
	 * Class constructor. Almost the same that the swt.widget.Composite
	 * constructor, check its documentation.
	 * 
	 * @param parent:
	 * 		The parent composite of this composite.
	 * @param style:
	 * 		The style of this composite.
	 */
	public MultiViewComposite(Composite parent, int style) {
		super(parent, style);
		this.setLayout(new GridLayout());
	}
	
	/**
	 * Change the actual view to the view of the index-th component.
	 * 
	 * @param index
	 * 		The position among the children of this MultiViewComposite of the
	 * 		requested view.
	 */
	public void changeView(int index) {
		Control child2show, child2hide;
		GridData grid;
		
		// Check bounds.
		if (index < 0 || index >= this.getChildren().length)
			throw new IndexOutOfBoundsException();
		
		// Check if both children are the same and do nothing.
		if (actual_view == index)
			return;
		
		// Hide the child, checks if actual_view is -1 (the MultiViewComposite
		// was recently created).
		if (actual_view != -1) {
			child2hide = this.getChildren()[actual_view];
			grid = new GridData(SWT.FILL, SWT.FILL, true, true);
			grid.exclude = true;
			child2hide.setVisible(false);
			child2hide.setLayoutData(grid);
		}
		
		// Show the child.
		child2show = this.getChildren()[index];
		if (child2show instanceof DustComposite)
			((DustComposite)child2show).show();
		else {
			grid = (GridData)this.getLayoutData();
			grid.exclude = false;
			child2show.setVisible(true);
			child2show.setLayoutData(grid);
		}
		
		// Update the actual view.
		this.layout();
		actual_view = index;
	}
}
